#ifndef _RESOURCEPAYLOAD_H_
#define _RESOURCEPAYLOAD_H_

#include <memory>
#include <string>
#include <functional>

namespace SEngine
{
    class Resource
    {
    public:
        virtual ~Resource() = default;
        std::string GetID();
    };

    template<typename T>
    class ResourcePayload;

    template<typename T>
    class ResourceRef
    {
    public:
        using Type = T;
        ResourceRef() {}
        ResourceRef(std::weak_ptr<ResourcePayload<T>> res) : m_data(res) {}
        virtual ~ResourceRef() = default;
        void Reset() { m_data.reset(); }
        explicit operator bool () const { return !m_data.expired(); }
        T & Value() { 
            return *m_data.lock()->m_data;
        }
        /**
         * @brief 真实路径
         */
        std::string Path() { return m_data.lock()->m_path; }
        /**
         * @brief 资源管理器的路径
         */
        std::string Name() { return m_data.lock()->m_name; }
        void Reload(std::function<std::unique_ptr<T>(const std::string & path, const std::string & name)> && fn) { m_data.lock()->m_data = fn(Path(), Name()); }
    private:
        std::weak_ptr<ResourcePayload<T>> m_data;
    };

    template<typename T>
    class ResourcePayload : public Resource, public std::enable_shared_from_this<ResourcePayload<T>>
    {
        friend class ResourceRef<T>;
    public:
        ResourcePayload(std::unique_ptr<T> && data) : m_data(std::move(data)) {}
        ResourcePayload(const std::string path, std::unique_ptr<T> && data) : m_path(path), m_data(std::move(data)) {}
        ResourcePayload(const std::string & name, const std::string & path, std::unique_ptr<T> && data) : m_name(name), m_path(path), m_data(std::move(data)) {}
        ResourcePayload(ResourcePayload && that) { *this = std::move(that); }
        ResourcePayload & operator = (ResourcePayload && that) { 
            this->m_data = std::move(that.m_data);
            this->m_name = std::move(that.m_name);
            this->m_path = std::move(that.m_path);
            return *this;
        }
        virtual ~ResourcePayload() = default;
        ResourceRef<T> GetRef() { return ResourceRef<T>(this->weak_from_this()); }
    private:
        std::unique_ptr<T> m_data;
        std::string m_path{""};
        std::string m_name{""};
    };

    template<typename T>
    using ResRef = ResourceRef<T>;

    template<typename T>
    struct Is_ResourcePayloadRef { static constexpr bool value = false; };

    template<typename T>
    struct Is_ResourcePayloadRef<ResRef<T>> { static constexpr bool value = true; };


    template<typename T>
    constexpr bool is_ResourcePayloadRef_v = Is_ResourcePayloadRef<T>::value;

    
} // namespace SEngine



#endif